package cn.lutu.domain.service.impl;

import cn.lutu.cache.ArticleCacheRepository;
import cn.lutu.domain.repository.ArticleCollectRepository;
import cn.lutu.domain.repository.ArticleRepository;
import cn.lutu.domain.repository.ArticleUpRepository;
import cn.lutu.domain.search.ArticleSearchRepository;
import cn.lutu.domain.service.ArticleService;
import cn.lutu.protocol.dto.ArticleCollectDTO;
import cn.lutu.protocol.dto.ArticlePostDTO;
import cn.lutu.protocol.dto.ArticleUpDTO;
import cn.lutu.protocol.entity.*;
import cn.lutu.protocol.search.ArticleSearchVO;
import cn.lutu.protocol.vo.*;
import cn.lutu.security.jwtFilter.CurrentPrincipal;
import cn.lutu.util.IPUtil;
import cn.lutu.util.common.PageInfoToPageDataConverter;
import cn.lutu.util.exception.ServiceException;
import cn.lutu.util.pojo.vo.PageData;
import cn.lutu.util.response.StatusCode;
import com.alibaba.druid.util.StringUtils;
import com.github.houbb.sensitive.word.bs.SensitiveWordBs;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchPage;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

@Slf4j
@Service
public class ArticleServiceImpl implements ArticleService {
    @Autowired
    private ArticleCacheRepository articleCacheRepository;

    @Value("${lutu.dao.default-query-page-size}")
    private Integer defaultQueryPageSize;

    @Autowired
    private ArticleRepository articleRepository;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private ArticleCollectRepository articleCollectRepository;

    @Autowired
    private ArticleUpRepository articleUpRepository;

    @Autowired
    private ArticleSearchRepository articleSearchRepository;




    @Override
    public void add_new(ArticlePostDTO articlePostDTO,Long userId) throws Exception {
        log.debug("开始处理发表文章业务"+articlePostDTO);

        String ip = request.getHeader("X-Forwarded-For");
        if (!StringUtils.isEmpty(ip)) {
            String[] ips = ip.split(",");
            ip = ips[0];
        } else {
            ip = request.getRemoteAddr();
        }
        //插入文章表

        String city = IPUtil.queryCityByIP(ip);
            // 使用查询到的国家和城市信息...

        String content = articlePostDTO.getContent();
        boolean contains = SensitiveWordBs.newInstance().contains(content);
        if(contains){
            String message = "您发布的文章包含敏感词汇,请重新编辑并提交";
            log.debug(message);
            throw new ServiceException(StatusCode.OPERATION_FAILED,message);
        }

        String title = articlePostDTO.getTitle();
        boolean contains1 = SensitiveWordBs.newInstance().contains(title);
        if(contains1){
            String message = "您发布的文章标题包含敏感词汇,请重新编辑并提交";
            log.debug(message);
            throw new ServiceException(StatusCode.OPERATION_FAILED,message);
        }
        Article article = new Article();
        ArticleContent articleContent = new ArticleContent();
        BeanUtils.copyProperties(articlePostDTO, article);
        article.setUserId(userId);
        article.setUpCount(0);
        article.setIp(city);
        article.setCollectCount(0);
        article.setCommentCount(0);
        article.setViewCount(0);
        article.setArticleCategoryId(articlePostDTO.getCategoryId());
        article.setContentId(1L);
        article.setCheckState(UNCHECK_ARTICLE);
        articleRepository.insert(article);

        //插入内容表
        articleContent.setContent(articlePostDTO.getContent());
        articleContent.setArticleId(article.getId());
        articleRepository.insertContent(articleContent);

        articleRepository.deleteById(articlePostDTO.getId());
    }

    @Override
    public PageData<ArticleListVO> selectAll(Integer pageNum, Integer pageSize) {
        log.debug("正在处理获取文章列表业务");
        List<ArticleListVO> articleList = articleCacheRepository.readArticle();
        PageInfo<ArticleListVO> pageInfo = new PageInfo<>(articleList);
        log.debug("pageInfo为{}",pageInfo);
        PageData<ArticleListVO> pageData = PageInfoToPageDataConverter.convert(pageInfo);
        log.debug("pageData{}",pageData);
        return pageData;
    }

    @Override
    public PageData<ArticleListVO> selectAll(Integer pageNum) {
        PageData<ArticleListVO> pageData = articleRepository.selectAll(pageNum, defaultQueryPageSize);
        return pageData;
    }

    @Override
    public List<ArticleListVO> selectHotArt() {
        log.debug("正在处理热门文章列表业务");
        return articleCacheRepository.readArticle();
    }

    @Override
    public List<ArticleListVO> selectRecent() {
        log.debug("正在处理最近文章列表业务");
        return articleCacheRepository.readArticle();
    }

    @Override
    public List<ArticleSearchStandardVO> selectSearch(String textSearch) {
        log.debug("正在处理搜索文章业务{}",textSearch);
        int page = 0;
        int size = 5;
        Pageable pageable = PageRequest.of(page, size);

        SearchPage<ArticleSearchVO> searchPage = articleSearchRepository.searchByTitleAndBrief(textSearch, textSearch, pageable);
        int number = searchPage.getNumber();
        int size1 = searchPage.getSize();
        int totalPages = searchPage.getTotalPages();

        log.info("number={}" ,number);
        log.info("size1={}",size1);
        log.info("totalPages={}",totalPages);
        List<ArticleSearchStandardVO> list = new ArrayList<>();
        List<SearchHit<ArticleSearchVO>> searchHits = searchPage.getContent();
        for (SearchHit<ArticleSearchVO> searchHit : searchHits) {
            ArticleSearchStandardVO articleSearchStandardVO = new ArticleSearchStandardVO();
            List<String> title1 = searchHit.getHighlightField("title");
            articleSearchStandardVO.setTitle(title1);
            ArticleSearchVO content = searchHit.getContent();
            articleSearchStandardVO.setArticleSearchVO(content);
            list.add(articleSearchStandardVO);

            log.info("title{}",title1);
            log.info("content{}",content);
            log.info("articleSearchStandardVO{}",articleSearchStandardVO);
        }
        if(list.size()==0){
            String message = "未搜到相关内容,请换个关键词重新试一试...";
            log.debug(message);
            throw new ServiceException(StatusCode.ERROR_NOT_FOUND,message);
        }
        return list;

    }


    @Override
    public List<HotListVO> selectHot() {
        log.debug("正在处理热门标题列表业务");
        return articleRepository.selectHot();
    }

    @Override
    public ArticleDetailVO selectArticleDetail(Long id,Long userId) {
        log.debug("正在处理获取文章详情业务");
        ArticleDetailVO articleDetailVO = articleRepository.selectArticleDetail(id);
        log.debug("查询到的文章详情为{}",articleDetailVO);

        Article article3 = new Article();
        article3.setId(id);
        article3.setViewCount(articleRepository.selectArticleDetail(id).getViewCount()+1);
        articleRepository.updateCollect(article3);

        if(userId==null){
            log.debug("无userId的返回");
            return articleDetailVO;
        }
        Integer rows = articleCollectRepository.countById(id, userId);
        if(rows == 1){
            articleDetailVO.setIsCollect(1);
        }else{
            articleDetailVO.setIsCollect(0);
        }

        Integer upRows = articleUpRepository.countById(id, userId);
        if(upRows == 1){
            articleDetailVO.setIsUp(1);
        }else{
            articleDetailVO.setIsUp(0);
        }
        return articleDetailVO;
    }


    @Override
    public void collect(ArticleCollectDTO articleCollectDTO) {
        Long userId = articleCollectDTO.getUserId();
        Long articleId = articleCollectDTO.getArticleId();

        ArticleCollectVO articleCollectVO = articleRepository.selectCollect(userId,articleId);
        if(articleCollectVO != null){
            log.debug("正在处理取消收藏文章业务");
            articleRepository.deleteCollectById(userId,articleId);
            Article article2 = new Article();
            int count = articleRepository.selectArticleDetail(articleId).getCollectCount();
            article2.setCollectCount(count-1);
            article2.setId(articleId);
            articleRepository.updateCollect(article2);
            return;
        }

        log.debug("正在处理收藏文章业务");
        Collect collect = new Collect();
        collect.setArticleId(articleId);
        collect.setUserId(userId);
        articleRepository.insertArticle(collect);

        Article article1 = new Article();
        int count = articleRepository.selectArticleDetail(articleId).getCollectCount();
        article1.setCollectCount(count+1);
        article1.setId(articleId);
        articleRepository.updateCollect(article1);
    }


    @Override
    public void up(ArticleUpDTO articleUpDTO) {

        Long userId = articleUpDTO.getUserId();
        Long articleId = articleUpDTO.getArticleId();

        ArticleUpVO articleUpVO = articleRepository.selectUp(userId,articleId);
        if(articleUpVO != null){
            log.debug("正在处理取消点赞文章业务");
            articleRepository.deleteUpById(userId,articleId);

            Article article3 = new Article();
            int count = articleRepository.selectArticleDetail(articleId).getUpCount();
            article3.setUpCount(count-1);
            article3.setId(articleId);
            articleRepository.updateCollect(article3);
            return;
        }

        log.debug("正在处理点赞文章业务");
        Up up = new Up();
        up.setArticleId(articleId);
        up.setUserId(userId);
        articleRepository.insertUp(up);

        Article article2 = new Article();
        int count = articleRepository.selectArticleDetail(articleId).getUpCount();
        article2.setUpCount(count+1);
        article2.setId(articleId);
        articleRepository.updateCollect(article2);
    }


    @Override
    public void deleteById(Long id) {
        log.debug("正在处理删除文章业务");
        articleRepository.deleteById(id);
        rebuildRedis();
        rebuildSearch();
    }

    @Override
    public PageData<ArticleOthersListVO> selectByUserId(Integer pageNum, Integer pageSize,Long userId) {
        log.debug("正在处理获取作者其他文章业务");
        PageData<ArticleOthersListVO> pageData = articleRepository.selectByUserId(pageNum, pageSize,userId);
        return pageData;
    }

    @Override
    public PageData<ArticleOthersListVO> selectByUserId(Integer pageNum, Long userId) {
        PageData<ArticleOthersListVO> pageData = articleRepository.selectByUserId(pageNum, defaultQueryPageSize,userId);
        return pageData;
    }

    @Override
    public PageData<ArticleOthersListVO> selectArticleUp(Integer pageNum, Integer pageSize, Long userId) {
        log.debug("正在处理获取个人点赞的文章列表业务");
        PageData<ArticleOthersListVO> pageData = articleRepository.selectArticleUp(pageNum, pageSize,userId);
        return pageData;
    }

    @Override
    public PageData<ArticleOthersListVO> selectArticleUp(Integer pageNum, Long userId) {
        log.debug("开始处理【查询个人点赞列表】的业务，页码：{}", pageNum);
        PageData<ArticleOthersListVO> pageData = articleRepository.selectArticleUp(pageNum, defaultQueryPageSize,userId);
        return pageData;
    }

    @Override
    public PageData<ArticleOthersListVO> selectArticleCollect(Integer pageNum, Integer pageSize,Long userId) {
        log.debug("正在处理获取个人收藏的文章列表业务");
        PageData<ArticleOthersListVO> pageData = articleRepository.selectArticleCollect(pageNum, pageSize,userId);
        return pageData;
    }

    @Override
    public PageData<ArticleOthersListVO> selectArticleCollect(Integer pageNum, Long userId) {
        log.debug("开始处理【查询个人收藏列表】的业务，页码：{}", pageNum);
        PageData<ArticleOthersListVO> pageData = articleRepository.selectArticleCollect(pageNum, defaultQueryPageSize,userId);
        return pageData;
    }

    @Override
    public PageData<ArticleListVO> selectUnCheck(Integer pageNum, Integer pageSize) {
        log.debug("正在处理获取个人收藏的文章列表业务");
        PageData<ArticleListVO> pageData = articleRepository.selectUnCheck(pageNum, pageSize);
        return pageData;
    }

    @Override
    public PageData<ArticleListVO> selectUnCheck(Integer pageNum) {
        log.debug("开始处理【查询待审核文章列表】的业务，页码：{}", pageNum);
        PageData<ArticleListVO> pageData = articleRepository.selectUnCheck(pageNum, defaultQueryPageSize);
        return pageData;
    }

    @Override
    public void updateCheck(Long articleId,String checkRemarks) {
        log.debug("正在处理通过文章审核业务");
        int rows = articleRepository.selectCount(articleId);
        if(rows != 1){
            String message = "该文章不存在,请重新提交";
            log.debug(message);
            throw new ServiceException(StatusCode.ERROR_NOT_FOUND,message);
        }
        Article article = new Article();
        article.setId(articleId);
        if(checkRemarks == null){
            article.setCheckState(CHECK_ARTICLE);
            articleRepository.updateCheck(article);
            rebuildRedis();
            rebuildSearch();
            return;
        }
        article.setCheckState(REJECT_ARTICLE);
        article.setCheckRemarks(checkRemarks);
        articleRepository.updateCheck(article);
        rebuildRedis();
        rebuildSearch();
    }

    @Override
    public List<ArticleListVO> rejectCheckList() {
        log.debug("正在处理获取审核不通过文章列表业务");
        return articleRepository.rejectCheckList();
    }

    @Override
    public List<ArticleListVO> rejectCheckListById(Long userId) {
        log.debug("正在处理获取个人审核不通过文章列表业务");
        return articleRepository.rejectCheckListById(userId);
    }

    @Override
    public void rebuildRedis() {
        log.debug("开始重建文章缓存");
        articleCacheRepository.delete();
        PageData<ArticleListVO> pageData = articleRepository.selectAll(1, Integer.MAX_VALUE);
        List<ArticleListVO> list = pageData.getList();
        articleCacheRepository.insertRedis(list);
    }

    @Override
    public void rebuildSearch() {
        log.debug("开始处理【更新搜索服务器中的文章列表】的业务，无参数");
        articleSearchRepository.deleteAll();
        Integer pageNum = 1;
        Integer pageSize = 10;
        Integer maxPage;
        PageData<ArticleSearchVO> pageData;
        do {
            pageData = articleRepository.listSearchVO(pageNum, pageSize);
            maxPage = pageData.getMaxPage();
            articleSearchRepository.saveAll(pageData.getList());
            pageNum++;
        } while (pageNum <= maxPage);
    }
}

